package com.game.gui {
	import com.game.data.Data;
	import com.game.data.TowerInitObject;
	import com.game.events.GameEvent;
	import com.game.path.PathFinder;
	
	import flash.display.BitmapData;
	import flash.display.GraphicsPathWinding;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
	
	import flashx.textLayout.formats.TextAlign;

	public class InterfaceControl extends Sprite {
		public static const TEXT_FILTER:DropShadowFilter = new DropShadowFilter(0, 0, 0x0, 1, 8, 8, 2);
		private var drawShp:TowerTempDrawShape = new TowerTempDrawShape();
		private var idToRemove:int = -1;
		private var removalControl:UpgradeRemovalControl;
		private var buttonsArray:Vector.<TowerSelectionButton>;
		private var exitButton:GeneralButton;
		private var pauseButton:GeneralButton;
		private var fastForwardButton:GeneralButton;
		private var volumeButton:GeneralButton;
		private var titleFormat:TextFormat;
		private var pointsTracer:TextField = new TextField();
		private var roundsTracer:TextField = new TextField();
		private var goneFreeTracer:TextField = new TextField();
		private var buttonCatcher:Sprite = new Sprite();
		private var smallTextFormat:TextFormat;
		private var data:Data;
		private var possibleLocation:Object = {x: -1, y: -1, block: true};
		public function InterfaceControl() {
			data = Data.getInstance();
			addChild(drawShp);
			smallTextFormat = new TextFormat(data.mainFont.fontName, 18, 0x855000, null, null, null, null, null, TextAlign.RIGHT)
			smallTextFormat.kerning = true;
			smallTextFormat.letterSpacing = 0.5;
			titleFormat = new TextFormat(data.mainFont.fontName, 36, 0xffffff, null, null, null, null, null, TextAlign.RIGHT)
			createButtons();
			removalControl = new UpgradeRemovalControl();
			removalControl.format = smallTextFormat;
			addChild(removalControl);
			removalControl.addEventListener(MouseEvent.CLICK, onRemoveClick);
			hideClose();
			addChild(pointsTracer);
			addChild(goneFreeTracer);
			addChild(roundsTracer);
			data.addEventListener(GameEvent.TOWER_DATA_SET, onTowerSelected);
			data.addEventListener(GameEvent.POINTS_UPDATED, onPointsUpdated);
			data.addEventListener(GameEvent.ROUNDS_UPDATED, onRoundsUpdated);
			data.addEventListener(GameEvent.GONE_FREE_UPDATED, onGoneFreeUpdated);
			data.dispatchEvent(new GameEvent(GameEvent.POINTS_UPDATED));
			data.dispatchEvent(new GameEvent(GameEvent.GONE_FREE_UPDATED));
			data.dispatchEvent(new GameEvent(GameEvent.ROUNDS_UPDATED));
		}
		public function onGoneFreeUpdated(e:Event):void {
			goneFreeTracer.text = "HP: " + data.goneFreeCounter;
			if(data.goneFreeCounter==0){
				resetPauseForwardButtons();
				this.dispatchEvent(new GameEvent(GameEvent.GAME_OVER));
			}
		}
		public function onRoundsUpdated(e:Event):void {
			roundsTracer.text = "ROUND: " + int(data.waveCounter + 1);
		}
		/**
		 * Updates number of points
		 * @param e GameEvent
		 *
		 */
		public function onPointsUpdated(e:Event):void {
			pointsTracer.text = "$: " + data.myPoints;
			checkButtonsAvail();
			checkUpgradeAvail();
		}
		/**
		 * Initiates interface interactions
		 *
		 */
		public function onAdded():void {
			this.stage.addEventListener(MouseEvent.CLICK, onSqrClick);
		}
		private function onDown(e:MouseEvent):void {
			hideClose();
			this.stage.addEventListener(MouseEvent.MOUSE_UP, onStageUp);
			this.drawShp.fillDrawShape(TowerSelectionButton(e.target).type);
			this.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMousMove);
			onMousMove(e);
		}
		/**
		 * Moves the drawShp to mouse screen position.
		 * Checks for location of the mouse against the level
		 *
		 * @param e
		 *
		 */
		private function onMousMove(e:MouseEvent):void {
			var posX:int = Math.max(Math.min(Math.floor(e.stageX / Data.STEP), data.myLevel[0].length - 1), 0);
			var posY:int = Math.max(Math.min(Math.floor(e.stageY / Data.STEP), data.myLevel.length - 1), 0);
			if (possibleLocation.x == posX && possibleLocation.y == posY) {
				return;
			}
			possibleLocation.x = posX;
			possibleLocation.y = posY;
			var block:Boolean = false;
			if (data.myLevel[posY] && data.myLevel[posY][posX] != 1 && data.myLevel[posY][posX] != 3 ) {
				data.myLevel[posY][posX] = 2;
				block = !Boolean(PathFinder.find(data.iniTilePoint, data.finTilePoint, data.myLevel))
				data.myLevel[posY][posX] = 0;
				possibleLocation.block = block;
			}
			drawShp.x = posX * Data.STEP;
			drawShp.y = posY * Data.STEP;
			if (data.myLevel[posY][posX] != 0 || block) {
				drawShp.allowFilter(true);
			} else {
				drawShp.allowFilter(false);
			}
		}
		private function checkButtonsAvail():void {
			for (var i:int = 0; i < buttonsArray.length; i++) {
				if (data.weapons[i].cost <= data.myPoints) {
					buttonsArray[i].mouseEnabled = true;
					buttonsArray[i].filters = []
				} else {
					buttonsArray[i].mouseEnabled = false;
					buttonsArray[i].filters = [Data.GRAY_SCALE];
				}
			}
		}
		/**
		 * Builds all Interface controlls
		 *
		 */
		private function createButtons():void {
			buttonsArray = new Vector.<TowerSelectionButton>();
			for (var i:int = 0; i < 6; i++) {
				createButton(i, smallTextFormat);
			}
			roundsTracer.embedFonts = goneFreeTracer.embedFonts = pointsTracer.embedFonts = true;
			roundsTracer.defaultTextFormat = goneFreeTracer.defaultTextFormat = pointsTracer.defaultTextFormat = titleFormat;
			goneFreeTracer.mouseEnabled = roundsTracer.mouseEnabled = pointsTracer.mouseEnabled = false;
			goneFreeTracer.y = roundsTracer.y = pointsTracer.y = 0;
			pointsTracer.x = 10;
			roundsTracer.x = pointsTracer.x + pointsTracer.width + 20;
			goneFreeTracer.x = roundsTracer.x + roundsTracer.width + 20;
			roundsTracer.filters = pointsTracer.filters = goneFreeTracer.filters = [TEXT_FILTER];
			//
			exitButton = createGeneralButton(0, data.iconArray[8]);
			pauseButton = createGeneralButton(1, data.iconArray[9], data.iconArray[10]);
			fastForwardButton = createGeneralButton(2, data.iconArray[11], data.iconArray[12]);
			//
			volumeButton = createGeneralButton(3, data.iconArray[13], data.iconArray[14]);
			volumeButton.x=data.stageWidth-Data.ICON_SIZE;
			volumeButton.y=0;
			volumeButton.active=true;
			//
			buttonCatcher.graphics.beginFill(0xff0000, 0.05);
			buttonCatcher.graphics.drawRect(0, data.stageHeight - Data.ICON_SIZE,  3 * Data.ICON_SIZE, Data.ICON_SIZE);
			buttonCatcher.graphics.endFill();
			buttonCatcher.graphics.beginFill(0xff0000, 0.05);
			buttonCatcher.graphics.drawRect(data.stageWidth, data.stageHeight - Data.ICON_SIZE, -(buttonsArray.length ) * Data.ICON_SIZE, Data.ICON_SIZE);
			buttonCatcher.graphics.endFill();
			buttonCatcher.graphics.beginFill(0xff0000, 0.05);
			buttonCatcher.graphics.drawRect(0, data.myLevel.length * Data.STEP, data.stageWidth, data.stageHeight-data.myLevel.length * Data.STEP);
			buttonCatcher.graphics.endFill();
			this.addChildAt(buttonCatcher, 0);
			//
		}
		private function createGeneralButton(num:int, one:BitmapData = null, two:BitmapData = null):GeneralButton {
			var button:GeneralButton = new GeneralButton(one, two);
			button.x = num * Data.ICON_SIZE;
			button.y = data.stageHeight - Data.ICON_SIZE;
			button.addEventListener(MouseEvent.MOUSE_OVER, onButtonOver);
			button.addEventListener(MouseEvent.MOUSE_OUT, onButtonOut);
			button.addEventListener(MouseEvent.CLICK, onGeneralButtonClick);
			this.addChild(button);
			return button;
		}
		/**
		 * Creates an individual button
		 *
		 * @param num Number of button
		 * @param frmt TextFormat
		 *
		 */
		private function createButton(num:int, frmt:TextFormat):void {
			buttonsArray.push(new TowerSelectionButton(data.weapons[num].type, data.iconArray[num], frmt, data.weapons[num].cost));
			this.addChild(buttonsArray[buttonsArray.length - 1])
			buttonsArray[buttonsArray.length - 1].addEventListener(MouseEvent.MOUSE_DOWN, onDown);
			buttonsArray[buttonsArray.length - 1].addEventListener(MouseEvent.MOUSE_UP, onButtonUp);
			buttonsArray[buttonsArray.length - 1].addEventListener(MouseEvent.MOUSE_OVER, onButtonOver);
			buttonsArray[buttonsArray.length - 1].addEventListener(MouseEvent.MOUSE_OUT, onButtonOut);
			buttonsArray[buttonsArray.length - 1].y = data.stageHeight - Data.ICON_SIZE;
			buttonsArray[buttonsArray.length - 1].x = data.stageWidth-((6-num) * Data.ICON_SIZE);
		}
		private function onGeneralButtonClick(e:MouseEvent):void {
			GeneralButton(e.target).active = !GeneralButton(e.target).active;
			switch (e.target) {
				case exitButton:
					resetPauseForwardButtons();
					this.dispatchEvent(new GameEvent(GameEvent.EXIT_GAME))
					break;
				case pauseButton:
					data.isPaused = pauseButton.active;
					break;
				case fastForwardButton:
					switchSpeed(fastForwardButton.active);
					break;
				case volumeButton:
					data.volume = volumeButton.active;
					break;
			}
		}
		private function resetPauseForwardButtons():void{
			fastForwardButton.active=false;
			pauseButton.active=false;
			data.isPaused = pauseButton.active;
			switchSpeed(fastForwardButton.active);
		}
		private function switchSpeed(value:Boolean):void{
			this.stage.frameRate=value?48:24;
		}
		private function onButtonOver(e:MouseEvent):void {
			e.target.over(true);
		}
		private function onButtonOut(e:MouseEvent):void {
			e.target.over(false);
		}
		private function onButtonUp(e:MouseEvent):void {
			//trace("onButtonUp");
			this.stage.removeEventListener(MouseEvent.MOUSE_UP, onStageUp);
			this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMousMove);
			e.stopImmediatePropagation();
			drawShp.clearShape();
		}
		/**
		 * Checks where user released a mouse
		 * If possition doesn't block path and isn't occupied by a tower, then place a tower;
		 * @param e
		 *
		 */
		private function onStageUp(e:MouseEvent):void {
			onButtonUp(e);
			if (e.target == buttonCatcher) {
				return;
			}
			if (possibleLocation.block || data.myLevel[possibleLocation.y][possibleLocation.x] == 1 || data.myLevel[possibleLocation.y][possibleLocation.x] == 3) {
				return;
			}
			data.myLevel[possibleLocation.y][possibleLocation.x] = 3;
			//passing tower data from shape to object
			data.towerData = new TowerInitObject(possibleLocation.x, possibleLocation.y, drawShp.type); //
			data.myPoints -= data.weapons[drawShp.type.ordinal].cost;
		}
		/**
		 * Checks for a tower under current mouse position.
		 *
		 * @param e MouseEvent
		 *
		 */
		private function onSqrClick(e:MouseEvent):void {
			var posX:int = Math.floor(e.stageX / Data.STEP);
			var posY:int = Math.floor(e.stageY / Data.STEP);
			removalControl.visible = false;
			// if position is inside level boundaries, then check selected cell for a tower
			if (data.myLevel[posY] && data.myLevel[posY][posX] != 0) {
				data.checkTowerAtPoint = new Point(posX, posY);
			}
		}
		private function onTowerSelected(e:Event):void {
			if (idToRemove == data.selectedTowerData.arrayId) {
				hideClose();
			} else {
				idToRemove = data.selectedTowerData.arrayId;
				showClose();
			}
		}
		private function hideClose():void {
			removalControl.visible = false;
			idToRemove = -1;
		}
		private function showClose():void {
			removalControl.visible = true;
			removalControl.x = data.checkTowerAtPoint.x * Data.STEP;
			removalControl.y = data.checkTowerAtPoint.y * Data.STEP;
			removalControl.drawClose();
		}
		private function checkUpgradeAvail():void {
			if (removalControl.visible) {
				removalControl.drawClose();
			}
		}
		private function onRemoveClick(e:MouseEvent):void {
			e.stopImmediatePropagation();
			this.removalControl.checkHit(e.localX, e.localY, idToRemove);
			hideClose();
		}
	}
}